/**
 * 开发者   : Marco
 * 创建时间 : 2016年6月1日, 下午8:39
 */

#include "md5.h"
#include <marco/md5.h>

#ifndef MARCO_NO_MD5
MARCOPP_NAMESPACE_BEGIN

/**
 * 实现类, 为了隐藏接口类编写细节
 */
class md5_impl {
public:
    explicit md5_impl(void) MARCOPP_USE_NOEXCEPT { // 构造并初始化
	md5_init(&s);
    }
    
    explicit md5_impl(const void* data, int nbytes) MARCOPP_USE_NOEXCEPT { // 构造并初始化
	md5_init(&s);
	md5_append(&s, data, nbytes);
    }
    
    md5_impl(const md5_impl& ths) {
	s = ths.s;
    }
    
    void reinit(void) throw() { md5_init(&s); }
    void append(const void* data, int nbytes) MARCOPP_USE_NOEXCEPT { md5_append(&s, data, nbytes); }
    void finish(unsigned char* result) throw() { md5_finish(&s, result); }
    
private:
    md5_state_t s;
};

md5::md5(void) : impl(new md5_impl()) { }
md5::md5(const void* data, int nbytes) : impl(new md5_impl(data, nbytes)) { }
md5::md5(const md5& ths) : impl(new md5_impl(*(ths.impl))) { }

#if (__cplusplus >= 201103L)
/**
 * 移动构造
 * @param ths
 */
md5::md5(md5&& ths) {
    impl = ths.impl;
    ths.impl = nullptr;
}
#endif

md5::~md5(void) { delete impl; }

/**
 * 重新初始化
 */
void md5::reinit(void) throw() {
    impl->reinit();
}

/**
 * 添加数据参与计算
 * @param data 数据内容
 * @param nbytes 数据长度
 */
void md5::append(const void* data, int nbytes) MARCOPP_USE_NOEXCEPT {
    impl->append(data, nbytes);
}

/**
 * 计算完成, 取结果
 * @param result 结果存储区(out)
 */
void md5::finish(unsigned char* result) MARCOPP_USE_NOEXCEPT {
    impl->finish(result);
}

/**
 * 计算指定的数据md5值的字节码形式
 * @param data 数据内容
 * @param nbytes 数据长度
 * @param result 结果存储区(out),至少16字节空间
 */
void md5::encodeByte(const void* data, int nbytes, unsigned char* result) MARCOPP_USE_NOEXCEPT {
    md5_encode_byte(data, nbytes, result);
}

/**
 * 计算指定的数据md5值的字符串形式
 * @param data 数据内容
 * @param nbytes 数据长度
 * @param result 结果存储区(out),至少33字节空间
 * @param lowercase 是否小写
 * @return 存储区首地址或NULL
 */
char* md5::encodeString(const void* data, int nbytes, char* result, bool lowercase) MARCOPP_USE_NOEXCEPT {
    return md5_encode_string(data, nbytes, result, (int)lowercase);
}

/**
 * 计算指定的文件md5值的字节码形式
 * @param pathname 文件路径
 * @param result 结果存储区(out),至少16字节空间
 * @return 1成功, 0失败(无法打开)
 */
int md5::fileEncodeByte(const char *pathname, unsigned char *result) MARCOPP_USE_NOEXCEPT {
    return md5_file_encode_byte(pathname, result);
}

/**
 * 计算指定的文件md5值的字符串形式
 * @param pathname 文件路径
 * @param result 结果存储区(out),至少33字节空间
 * @param lowercase 是否小写
 * @return 存储区首地址或NULL
 */
char* md5::fileEncodeString(const char *pathname, char *result, bool lowercase) MARCOPP_USE_NOEXCEPT {
    return md5_file_encode_string(pathname, result, (int)lowercase);
}

/**
 * 拷贝赋值运算符重载
 * @param ths 其它对象
 * @return 本对象引用
 */
md5& md5::operator=(const md5& ths) {
    if (this != &ths) {
	impl = new md5_impl(*(ths.impl));
    }
    
    return *this;
}

#if (__cplusplus >= 201103L)
/**移动赋值运算符重载*/
md5& md5::operator=(md5&& ths) {
    impl = ths.impl;
    ths.impl = nullptr;
    return *this;
}
#endif

MARCOPP_NAMESPACE_END
#endif // MARCO_NO_MD5